import std.math;


public {
   double noise(double x, double y, double z) {
      int X = cast(int)floor(x) & 255, 
          Y = cast(int)floor(y) & 255, 
          Z = cast(int)floor(z) & 255;
      x -= floor(x);         
      y -= floor(y);       
      z -= floor(z);
      double u = fade(x),       
             v = fade(y),     
             w = fade(z);
      int A = p[X  ]+Y, AA = p[A]+Z, AB = p[A+1]+Z,   
          B = p[X+1]+Y, BA = p[B]+Z, BB = p[B+1]+Z;  

      return lerp(w, lerp(v, lerp(u, grad(p[AA  ], x  , y  , z   ),  
                                     grad(p[BA  ], x-1, y  , z   )), 
                             lerp(u, grad(p[AB  ], x  , y-1, z   ),  
                                     grad(p[BB  ], x-1, y-1, z   ))),
                     lerp(v, lerp(u, grad(p[AA+1], x  , y  , z-1 ), 
                                     grad(p[BA+1], x-1, y  , z-1 )), 
                             lerp(u, grad(p[AB+1], x  , y-1, z-1 ),
                                     grad(p[BB+1], x-1, y-1, z-1 ))));
   }


   double fullNoise(double x, double y, double z, double frequency = 1.0, int octaves = 1, double persistence = 0.25) {
		double res = 0.0;
		double p = persistence;
		double amplitude = 1.0;

		for (int i = 0; i < octaves; ++i, amplitude *= p, frequency *= 2.0) {
			res += noise(x * frequency, y * frequency, z * frequency) * amplitude;
		}

		return res;
   }
}


private {
   double fade(double t) { return t * t * t * (t * (t * 6 - 15) + 10); }
   double lerp(double t, double a, double b) { return a + t * (b - a); }
   double grad(int hash, double x, double y, double z) {
      int h = hash & 15;                      // CONVERT LO 4 BITS OF HASH CODE
      double u = h<8 ? x : y,                 // INTO 12 GRADIENT DIRECTIONS.
             v = h<4 ? y : h==12||h==14 ? x : z;
      return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
   }


	int[] p;
	int[] permutation = [ 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225 ];

	
	static this() {
		p = new int[512];
		for(int j=0; j < 32; j++)
	   for (int i=0; i < 16 ; i++)
		   p[i+j*16] = permutation[i];
	}
}
